package soundCapture;

import gui.Login;

import javax.swing.*;

import java.awt.event.*;
import java.io.*;

import javax.sound.sampled.*;

public class Capture {

	protected boolean running;
	ByteArrayOutputStream out;

	// format of audio file
	AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
	final JButton capture = new JButton("Capture");
	final JButton stop = new JButton("Stop");
	final JButton save = new JButton("Save");
	final JButton open = new JButton("Open");
	final JButton play = new JButton("Play");
	boolean isPlaying = false;
	boolean isRecording = false;

	public Capture() {
		capture.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				capture.setEnabled(false);
				stop.setEnabled(true);
				save.setEnabled(false);
				open.setEnabled(false);
				play.setEnabled(false);
				captureAudio();
			}
		});

		stop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				capture.setEnabled(true);
				stop.setEnabled(false);
				save.setEnabled(true);
				open.setEnabled(true);
				play.setEnabled(true);
				stopAudio();
			}
		});

		save.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				saveAudio("RecordAudio");
			}
		});

		open.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				openAudio("RecordAudio");
				if (canPlay())
					play.setEnabled(true);
			}
		});

		play.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				capture.setEnabled(false);
				save.setEnabled(false);
				open.setEnabled(false);
				stop.setEnabled(true);
				if (!isPlaying)
					playAudio();
			}
		});
	}

	public void openAudio(String absolutePath) {
		try {
			// path of the wav file
			File wavFile = new File(absolutePath);
			InputStream is = new FileInputStream(wavFile);
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			int reads = is.read();
			while (reads != -1) {
				baos.write(reads);
				reads = is.read();
			}
			out = baos;
			is.close();
		} catch (FileNotFoundException e) {
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}

	public boolean saveAudio(String filename) {
		if (canPlay()) {
			try {
				// path of the wav file
				File wavFile = new File(Login.data_dir + filename + ".wav");
				FileOutputStream fos = new FileOutputStream(wavFile);
				out.writeTo(fos);
				fos.close();
				return true;
			} catch (IOException ioe) {
				ioe.printStackTrace();
				return false;
			}
		}
		return true;
	}

	public void stopAudio() {
		isPlaying = false;
		isRecording = false;
		running = false;

	}

	public void captureAudio() {
		try {
			final AudioFormat format = getFormat();
			DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
			final TargetDataLine line = (TargetDataLine) AudioSystem
					.getLine(info);
			line.open(format);
			line.start();
			isRecording = true;
			Runnable runner = new Runnable() {
				int bufferSize = (int) format.getSampleRate()
						* format.getFrameSize();
				byte buffer[] = new byte[bufferSize];

				public void run() {
					out = new ByteArrayOutputStream();
					running = true;
					try {
						while (running) {
							int count = line.read(buffer, 0, buffer.length);
							if (count > 0) {
								out.write(buffer, 0, count);
							}
						}
						line.close();
						out.close();
						isRecording = false;
					} catch (IOException e) {
						System.err.println("I/O problems: " + e);
						System.exit(-1);
					}
				}
			};
			Thread captureThread = new Thread(runner);
			captureThread.start();
		} catch (LineUnavailableException e) {
			System.err.println("Line unavailable: " + e);
			System.exit(-2);
		}
	}

	public void playAudio() {
		try {
			byte audio[] = out.toByteArray();
			InputStream input = new ByteArrayInputStream(audio);
			final AudioFormat format = getFormat();
			final AudioInputStream ais = new AudioInputStream(input, format,
					audio.length / format.getFrameSize());
			DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
			final SourceDataLine line = (SourceDataLine) AudioSystem
					.getLine(info);
			line.open(format);
			line.start();
			isPlaying = true;
			Runnable runner = new Runnable() {
				int bufferSize = (int) format.getSampleRate()
						* format.getFrameSize();
				byte buffer[] = new byte[bufferSize];

				public void run() {
					running = true;
					try {
						int count;
						while (canPlay()
								&& running
								&& (count = ais.read(buffer, 0, buffer.length)) != -1) {
							if (count > 0) {
								line.write(buffer, 0, count);
							}
						}
						line.drain();
						line.close();
						isPlaying = false;
					} catch (IOException e) {
						System.err.println("I/O problems: " + e);
						System.exit(-3);
					}
				}
			};
			Thread playThread = new Thread(runner);
			playThread.start();
		} catch (LineUnavailableException e) {
			System.err.println("Line unavailable: " + e);
			System.exit(-4);
		}
	}

	private AudioFormat getFormat() {
		float sampleRate = 44100;
		int sampleSizeInBits = 16;
		int channels = 1;
		boolean signed = true;
		boolean bigEndian = true;
		return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
				bigEndian);
	}

	public boolean isPlaying() {
		return isPlaying;
	}

	public boolean isRecording() {
		return isRecording;
	}

	public boolean canPlay() {
		try {
			return out.size() != 0;
		} catch (NullPointerException e) {
			return false;
		}
	}
}